﻿
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Windows.Data;

using OpenCvSharp;

using Xc.DataAccess.CodeReader.Properties;
using Xc.DataAccess.Core;
using YamlDotNet.Core.Tokens;
using System.Linq;
using System.Threading.Tasks;

namespace Xc.DataAccess.CodeReader.Models.Filters
{
    /// <summary>
    /// 过滤器基类
    /// </summary>
    public abstract class FilterBase : ViewModelBase
    {
        private Result executeResult;
        private Mat resultMat;
        private double cpuTickCount;
        private double width;
        private double height;

        /// <summary>
        /// 使用管道
        /// </summary>
        /// <param name="mat"></param>
        /// <param name="filterInfos">过滤器列表</param>
        /// <param name="preFilterBase">调用的上一个处理器</param>
        /// <returns></returns>
        internal abstract ResultData<Mat> UseChannel(Mat mat, FilterBase[] filterInfos, FilterBase preFilterBase);
        internal ResultData<Mat> Use(Mat mat, FilterBase[] filterInfos, FilterBase preFilterBase)
        {
            var tickStart = Cv2.GetCpuTickCount();

            try
            {
                var d = UseChannel(mat.Clone(), filterInfos, preFilterBase);
                ExecuteResult = d;
                if (ExecuteResult != null && ExecuteResult.IsSuccess)
                {
                    ResultMat = d.Data;
                    Width = d.Data.Width;
                    Height = d.Data.Height;
                }
                return d;
            }
            catch (Exception err)
            {
                ExecuteResult = Result.Reject(err.Message);
                return ResultData<Mat>.Reject(err.Message, null);
            }
            finally
            {
                var tickEnd = Cv2.GetCpuTickCount();
                CpuTickCount = tickEnd - tickStart;
            }
        }
        [OutputParameter("宽")]
        public double Width
        {
            get => width; private set
            {
                width = value; RaisedPropertyChanged();
            }
        }
        [OutputParameter("高")]
        public double Height
        {
            get => height; private set
            {
                height = value; RaisedPropertyChanged();
            }
        }
        /// <summary>
        /// CPU周期
        /// </summary>
        [OutputParameter("Cpu时钟计数")]
        public double CpuTickCount
        {
            get => cpuTickCount; private set
            {
                cpuTickCount = value;
                RaisedPropertyChanged();
            }
        }
        /// <summary>
        /// 任务执行前调用
        /// </summary>
        [IgnoreParameter]
        public ExecuteParamater BeforeExecute { get; set; }
        /// <summary>
        /// 执行完成后调用
        /// </summary>
        [IgnoreParameter]
        public ExecuteParamater AfterExecute { get; set; }
        /// <summary>
        /// 执行结果
        /// </summary>
        [OutputParameter("执行状态")]
        public Result ExecuteResult
        {
            get => executeResult; private set
            {
                executeResult = value;
                RaisedPropertyChanged();
            }
        }
        /// <summary>
        /// 执行后的图像
        /// </summary>
        [OutputParameter("执行后图像")]
        public Mat ResultMat
        {
            get => resultMat; set
            {
                resultMat = value;
                RaisedPropertyChanged();
            }
        }
        /// <summary>
        /// 服务序号
        /// </summary>
        [IgnoreParameter]
        public int ServiceIndex { get; set; }
        /// <summary>
        /// 过滤器信息
        /// </summary>
        [IgnoreParameter]
        public FilterAttribute FilterInfo
        {
            get
            {
                return (FilterAttribute)Attribute.GetCustomAttribute(this.GetType(), typeof(FilterAttribute));
            }
        }
        [IgnoreParameter]
        public InputParameter[] InputParameters
        {
            get
            {
                List<InputParameter> inputParameters = new List<InputParameter>();
                var properties = this.GetType().GetProperties();
                foreach (var property in properties)
                {
                    var ignore = (IgnoreParameterAttribute)Attribute.GetCustomAttribute(property, typeof(IgnoreParameterAttribute));
                    if (ignore != null)
                    {
                        continue;
                    }
                    var input = (InputParameterAttribute)Attribute.GetCustomAttribute(property, typeof(InputParameterAttribute));
                    if (input != null)
                    {
                        inputParameters.Add(new InputParameter(this, property.GetValue(this), input.Name, property.Name, input.ParameterType, property.PropertyType));
                    }
                }
                return inputParameters.ToArray();
            }
        }
        /// <summary>
        /// 输出参数
        /// </summary>
        [IgnoreParameter]
        public OutPutParameter[] OutPutParameters
        {
            get
            {
                List<OutPutParameter> inputParameters = new List<OutPutParameter>();
                var properties = this.GetType().GetProperties();
                foreach (var property in properties)
                {
                    var ignore = (IgnoreParameterAttribute)Attribute.GetCustomAttribute(property, typeof(IgnoreParameterAttribute));
                    if (ignore != null)
                    {
                        continue;
                    }
                    var input = (OutputParameterAttribute)Attribute.GetCustomAttribute(property, typeof(OutputParameterAttribute));
                    if (input != null)
                    {
                        inputParameters.Add(new OutPutParameter(this, input.Name, property.Name, property.PropertyType));
                    }
                }
                return inputParameters.ToArray();
            }
        }
        /// <summary>
        /// 获取可枚举的值
        /// </summary>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        public object[] GetEnumValues(string propertyName)
        {
            var pro = this.GetType().GetProperty(propertyName);
            if (pro.PropertyType.IsEnum)
            {
                return Enum.GetNames(pro.PropertyType);
            }
            else
            {
                if (pro.PropertyType.IsEnum==false&&pro.PropertyType.IsClass==false)
                {
                    var c= pro.PropertyType.GetFields(BindingFlags.Public | BindingFlags.Static).Select(p => p.Name).ToArray();
                    return c;
                }
                return null;
            }
        }
        /// <summary>
        /// 设置值
        /// </summary>
        /// <param name="propertyName"></param>
        /// <param name="propertyValue"></param>
        public void SetValue(string propertyName, object propertyValue)
        {
            var property = this.GetType().GetProperty(propertyName);
            if (property != null)
            {
                object value = null;
                if (propertyValue == null)
                {
                    value = propertyValue;
                }
                else if (propertyValue.GetType() != property.GetType())
                {
                    var type = property.PropertyType;
                    if (type.Name == typeof(string).Name)
                    {
                        value = propertyValue.ToString();
                    }
                    else if (type.Name == typeof(double).Name)
                    {
                        if (double.TryParse(propertyValue.ToString(), out var n))
                        {
                            value = n;
                        }
                        else
                        {
                            value = 0;
                        }
                    }
                    else if (type.Name == typeof(bool).Name)
                    {
                        if (bool.TryParse(propertyValue.ToString(), out var d))
                        {
                            value = d;
                        }
                    }
                    else if (type.Name == typeof(CVSize).Name)
                    {
                        value = propertyValue;
                    }
                    else if (type.Name == typeof(CVPoint).Name)
                    {
                        value = propertyValue;
                    }
                    else if (type.Name == typeof(int).Name)
                    {
                        if (int.TryParse(propertyValue.ToString(), out var d))
                        {
                            value = d;
                        }
                    }
                    else if (type.Name == typeof(Int16).Name)
                    {
                        if (Int16.TryParse(propertyValue.ToString(), out var d))
                        {
                            value = d;
                        }
                    }
                    else if (type.Name == typeof(Single).Name)
                    {
                        if (Single.TryParse(propertyValue.ToString(), out var n))
                        {
                            value = n;
                        }

                    }
                    else if (type.Name == typeof(FourCC).Name&& propertyValue.GetType().Name==typeof(Int32).Name)
                    {
                        value = new FourCC((int)propertyValue);

                    }
                    else if (type.IsEnum)
                    {
                        if (!Enum.IsDefined(type, propertyValue?.ToString()))
                        {
                            return;
                        }
                        value = Enum.Parse(type, propertyValue?.ToString());
                    }
                    else
                    {
                        value = propertyValue;
                    }
                }
                else
                {
                    value = propertyValue;
                }
                property.SetValue(this, value);
            }
        }
        /// <summary>
        /// 读取值
        /// </summary>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        public object GetValue(string propertyName)
        {
            return this.GetType().GetProperty(propertyName).GetValue(this);
        }
    }

}
